package com.roads.project.service.impl;

import com.roads.common.constant.Constants;
import com.roads.common.exception.ServiceException;
import com.roads.common.utils.BoqUtils;
import com.roads.common.utils.StringUtils;
import com.roads.project.domain.ProBoqArrange;
import com.roads.project.domain.template.ProBoqArrangeTemplate;
import com.roads.project.mapper.ProBoqArrangeMapper;
import com.roads.project.service.IProBoqArrangeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 清单整理Service业务层处理
 * 
 * @author nhp
 * @date 2021-11-22
 */
@Service
public class ProBoqArrangeServiceImpl implements IProBoqArrangeService {

    @Autowired
    private ProBoqArrangeMapper proBoqArrangeMapper;

    /**
     * 查询清单整理列表
     * 
     * @param proBoqArrange 清单整理
     * @return 清单整理
     */
    @Override
    public List<ProBoqArrange> selectProBoqArrangeList(ProBoqArrange proBoqArrange) {
        return proBoqArrangeMapper.selectProBoqArrangeList(proBoqArrange);
    }

    /**
     * 清单导入
     *
     * @param dataList 集合
     * @param userName 登录用户
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importData(List<ProBoqArrangeTemplate> dataList, String userName) {
        if (!StringUtils.isNotNull(dataList) || dataList.size() == 0) {
            throw new ServiceException("导入数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        int index = 2;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        List<ProBoqArrange> insertDataList = new ArrayList<>();
        for (ProBoqArrangeTemplate arrangeTemplate : dataList) {
            StringBuilder rowFailureMsg = new StringBuilder();
            boolean failureFlag = false;
            try {
                // 清单编号是否为空，格式是否正确
                if (StringUtils.isNotEmpty(arrangeTemplate.getBoqCode())) {
                    arrangeTemplate.setBoqCode(arrangeTemplate.getBoqCode().trim());
                }
                String boqCode = arrangeTemplate.getBoqCode();
                if (StringUtils.isEmpty(boqCode)) {
                    failureFlag = true;
                    StringUtils.appendFailureMsg(rowFailureMsg, index, "清单编号不能为空");
                } else {
                    if (!BoqUtils.validateBoqCode(boqCode)) {
                        failureFlag = true;
                        StringUtils.appendFailureMsg(rowFailureMsg, index, "清单编号格式不正确");
                    }
                }
                // 清单名称是否为空
                String boqName = arrangeTemplate.getBoqName();
                if (StringUtils.isEmpty(boqName)) {
                    failureFlag = true;
                    StringUtils.appendFailureMsg(rowFailureMsg, index, "清单名称不能为空");
                }
                // 创建对象
                ProBoqArrange proBoqArrange = new ProBoqArrange();
                proBoqArrange.setBoqCode(arrangeTemplate.getBoqCode());
                proBoqArrange.setBoqName(arrangeTemplate.getBoqName());
                proBoqArrange.setUnit(arrangeTemplate.getUnit());
                proBoqArrange.setAmount(arrangeTemplate.getAmount());
                proBoqArrange.setPrice(arrangeTemplate.getPrice());
                proBoqArrange.setTotal(arrangeTemplate.getTotal());
                proBoqArrange.setStatus(BoqUtils.BOQ_STATUS_INIT);
                proBoqArrange.setDescribe(arrangeTemplate.getDescribe());
                proBoqArrange.setReason(BoqUtils.BOQ_STATUS_INIT_TEXT);
                proBoqArrange.setCreateBy(userName);
                insertDataList.add(proBoqArrange);
                index++;
                if (failureFlag) {
                    failureNum ++;
                    failureMsg.append(rowFailureMsg);
                } else {
                    successNum++;
                }
            } catch (Exception e) {
                failureNum++;
                rowFailureMsg.append(StringUtils.appendFailureMsg(rowFailureMsg, index, e.getMessage()));
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            // 清库
            ProBoqArrange proBoqArrange = new ProBoqArrange();
            proBoqArrange.setCreateBy(userName);
            proBoqArrangeMapper.cleanByCreateBy(proBoqArrange);
            // 批量增加
            proBoqArrangeMapper.insertBatch(insertDataList);
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条。");
        }
        return successMsg.toString();
    }

    /**
     * 首次整理，主要整理清单父项和排序
     *
     * @param userName 登录用户
     */
    @Override
    public void arrange(String userName) {
        // 查询该用户下的所有清单
        ProBoqArrange search = new ProBoqArrange();
        search.setCreateBy(userName);
        List<ProBoqArrange> dataList = proBoqArrangeMapper.selectProBoqArrangeList(search);
        if (StringUtils.isNull(dataList) || dataList.size() == 0) {
            throw new ServiceException("未导入清单，不能进行整理");
        }
        // 转map，方便获取
        Map<String, ProBoqArrange> mapData = new HashMap<String, ProBoqArrange>(dataList.size());
        for (ProBoqArrange proBoqArrange : dataList) {
            mapData.put(proBoqArrange.getBoqCode(), proBoqArrange);
        }
        // 循环处理清单
        int orderNum = 1;
        for (ProBoqArrange arrange : dataList) {
            // 首先判断清单是否为缺省清单
            String boqCode = arrange.getBoqCode();
            if (BoqUtils.validateMissingBoqCode(boqCode)) {
                arrange.setStatus(BoqUtils.BOQ_STATUS_DEFECT);
                arrange.setReason(BoqUtils.BOQ_STATUS_DEFECT_TEXT);
            } else {
                // 暂定为正常清单
                arrange.setStatus(BoqUtils.BOQ_STATUS_NORMAL);
                arrange.setReason("");
                // 判断清单编号是否为大类
                if (BoqUtils.validateIsType(boqCode)) {
                    arrange.setLevel(1);
                    arrange.setParentCode("0");
                    arrange.setStatus(BoqUtils.BOQ_STATUS_NORMAL);
                    arrange.setReason("");
                } else {
                    // 非大类清单逻辑
                    String parentCode = calcBoqParentCode(boqCode, mapData);
                    arrange.setParentCode(parentCode);
                }
            }
            arrange.setUpdateBy(userName);
            arrange.setOrderNum(orderNum);
            orderNum += 5;
        }
        proBoqArrangeMapper.updateBatch(dataList);
        // 获取该用户下所有父项清单
        List<ProBoqArrange> parentDataList = proBoqArrangeMapper.selectParentProBoqArrangeList(userName);
        // 将父项清单转map
        Map<String, ProBoqArrange> parentMapData = new HashMap<>(parentDataList.size());
        for (ProBoqArrange proBoqArrange : parentDataList) {
            parentMapData.put(proBoqArrange.getBoqCode(), proBoqArrange);
        }
        // 二次整理，主要整理，清单祖籍,级别,是否叶节点
        secondArrange(dataList, mapData, parentMapData);
        // 三次整理，主要整理错误清单
        thirdArrange(dataList, mapData);
    }

    /**
     * 二次整理，主要整理，清单祖籍,级别,是否叶节点
     *
     * @param dataList 数据集
     * @param mapData 数据map
     * @param parentMapData 父项数据map
     */
    private void secondArrange(List<ProBoqArrange> dataList, Map<String, ProBoqArrange> mapData, Map<String, ProBoqArrange> parentMapData) {
        // 循环处理
        for (ProBoqArrange arrange : dataList) {
            // 缺省清单暂时跳过设置
            if (arrange.getStatus() == BoqUtils.BOQ_STATUS_DEFECT) {
                continue;
            }
            String boqCode = arrange.getBoqCode();
            // 父项编号为0时，可以直接设置级别和祖籍
            if ("0".equals(arrange.getParentCode())) {
                arrange.setAncestors(boqCode);
            } else {
                StringBuffer ancestors = new StringBuffer();
                appendAncestors(ancestors, arrange.getParentCode(), mapData);
                arrange.setAncestors(ancestors.substring(1, ancestors.length()) + "," + boqCode);
            }
            // 有单位的为叶子节点
            if (StringUtils.isNotEmpty(arrange.getUnit())) {
                arrange.setLeafNode(Constants.YES);
            } else {
                arrange.setLeafNode(Constants.NO);
            }
            // 设置级别
            if ("0".equals(arrange.getParentCode())) {
                arrange.setLevel(1);
            } else {
                int level = arrange.getAncestors().split(",").length;
                arrange.setLevel(level);
            }
        }
        proBoqArrangeMapper.updateBatch(dataList);
    }

    private void appendAncestors(StringBuffer ancestors, String parentCode, Map<String, ProBoqArrange> mapData) {
        ProBoqArrange proBoqArrange = mapData.get(parentCode);
        if (Constants.SUCCESS.equals(proBoqArrange.getParentCode())) {
            ancestors.insert(0, "," + proBoqArrange.getBoqCode());
        } else {
            ancestors.insert(0, "," + proBoqArrange.getBoqCode());
            appendAncestors(ancestors, proBoqArrange.getParentCode(), mapData);
        }
    }

    private void thirdArrange(List<ProBoqArrange> dataList, Map<String, ProBoqArrange> mapData) {
        Map<String, ProBoqArrange> handleData = new HashMap<>();
        // 循环处理
        for (ProBoqArrange arrange : dataList) {
            // 缺省清单暂时跳过设置
            if (arrange.getStatus() == BoqUtils.BOQ_STATUS_DEFECT) {
                continue;
            }
            String boqCode = arrange.getBoqCode();
            // 分割
            String[] boqCodeArray = boqCode.split("-");
            // 只处理2级以上的清单
            if (boqCodeArray.length > 2) {
                String parentCode = boqCode.substring(0, boqCode.lastIndexOf("-"));
                ProBoqArrange parent = mapData.get(parentCode);
                if (parent == null) {
                    arrange.setStatus(BoqUtils.BOQ_STATUS_NO_PARENT);
                    arrange.setReason(BoqUtils.BOQ_STATUS_NO_PARENT_TEXT + "：" + parentCode);
                    continue;
                }
            }
            // 查看是否重复清单
            ProBoqArrange repeatData = handleData.get(boqCode);
            if (repeatData != null) {
                arrange.setStatus(BoqUtils.BOQ_STATUS_REPEAT_CODE);
                arrange.setReason(BoqUtils.BOQ_STATUS_REPEAT_CODE_TEXT);
                continue;
            }
            // 检查数据是否正确
            if (Constants.YES.equals(arrange.getLeafNode())) {
                if (!BoqUtils.validateValue(arrange.getUnit(), arrange.getAmount(), arrange.getPrice(), arrange.getTotal())) {
                    arrange.setStatus(BoqUtils.BOQ_STATUS_INCOMPLETE);
                    arrange.setReason(BoqUtils.BOQ_STATUS_INCOMPLETE_TEXT);
                }
            }
            handleData.put(arrange.getBoqCode(), arrange);
        }
        proBoqArrangeMapper.updateBatch(dataList);
    }



    /**
     * 计算父项清单编号
     *
     * @param boqCode 清单编号
     * @param mapData 数据集
     * @return 父项清单编号
     */
    private String calcBoqParentCode(String boqCode, Map<String, ProBoqArrange> mapData) {
        // 分割
        String[] boqCodeArray = boqCode.split("-");
        int size = boqCodeArray.length - 1;
        for (int i = 0; i < boqCodeArray.length - 1; i++) {
            String arrangeCode = arrangeCode(boqCodeArray, size);
            // 用组装出来的清单编号去集合查找，如果找到，则定义为父项编号
            ProBoqArrange proBoqArrange = mapData.get(arrangeCode);
            if (null != proBoqArrange) {
                return arrangeCode;
            }
        }
        // 取清单的第一数字的大类作为父项编号
        return calcBoqType(boqCode);
    }

    /**
     * 递减计算父项清单
     * @param array 分割后的清单
     * @param count 循环次数
     * @return 重新组装的清单编号
     */
    private String arrangeCode(String[] array, int count) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < count; i++) {
            if (i == count - 1) {
                sb.append(array[i]);
            } else {
                sb.append(array[i] + "-");
            }
        }
        return sb.toString();
    }

    /**
     * 根据清单首数字获取大类清单
     * @param boqCode 清单编号
     * @return 大类编号
     */
    private String calcBoqType(String boqCode) {
        String boqCodeFirst = boqCode.substring(0, 1);
        for (int i = 0; i < BoqUtils.BOQ_CODE_TYPE.length; i++) {
            String typeName = BoqUtils.BOQ_CODE_TYPE[i];
            String typeFirst = typeName.substring(0, 1);
            if (boqCodeFirst.equals(typeFirst)) {
                return typeName;
            }
        }
        return "0";
    }

    @Override
    public void clean(String userName) {
        ProBoqArrange search = new ProBoqArrange();
        search.setCreateBy(userName);
        proBoqArrangeMapper.cleanByCreateBy(search);
    }

    /**
     * 忽略异常
     *
     * @param id 主键id
     */
    @Override
    public void ignore(long id) {
        proBoqArrangeMapper.ignore(id);
    }

    /**
     * 忽略警告
     *
     * @param userName 登录用户
     */
    @Override
    public void ignoreWarnings(String userName) {
        proBoqArrangeMapper.ignoreWarnings(userName);
    }

    /**
     * 根据ID查询距离最近的清单 不是叶子节点的正常清单
     *
     * @param id 清单ID
     * @return 结果
     */
    @Override
    public ProBoqArrange getLatelyById(Long id) {
        return proBoqArrangeMapper.getLatelyById(id);
    }

    /**
     * 自动补全清单代码
     *
     * @param id 父项ID
     * @param bId 补全清单ID
     * @param userName 登录用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void autoComplement(Long id, Long bId, String userName) {
        // 获取父项清单
        ProBoqArrange parentBoq = proBoqArrangeMapper.selectProBoqArrangeByBoqId(id);
        // 获取补全清单
        ProBoqArrange boq = proBoqArrangeMapper.selectProBoqArrangeByBoqId(bId);
//        // 设置父项
//        parentBoq.setLeafNode(Constants.NO);
//        parentBoq.setStatus(BoqUtils.BOQ_STATUS_NORMAL);
//        parentBoq.setReason("");
        // 设置补全清单
        if (StringUtils.isNotEmpty(boq.getUnit())) {
            boq.setLeafNode(Constants.YES);
        } else {
            boq.setLeafNode(Constants.NO);
        }
        String newBoqCode = "";
        String parentCode = parentBoq.getBoqCode();
        boq.setAutoCompletion(Constants.YES);
        boq.setLevel(parentBoq.getLevel() + 1);
        boq.setParentCode(parentBoq.getBoqCode());
        String boqCode = boq.getBoqCode();
        String parentCodeSuffix = parentCode.substring(parentCode.lastIndexOf("-"));
        if (boqCode.startsWith(parentCodeSuffix)) {
            newBoqCode = parentCode + boqCode.substring(parentCodeSuffix.length());
        } else {
            newBoqCode = parentCode + boqCode;
        }
        boq.setBoqCode(newBoqCode);
        boq.setAncestors(parentBoq.getAncestors() + "," + newBoqCode);
        boq.setCompletionCode(parentBoq.getBoqCode());
        // 查看新清单是否存在
        List<ProBoqArrange> result = proBoqArrangeMapper.selectProBoqArrangeByCode(newBoqCode, userName);
        if (result.size() > 0) {
            boq.setStatus(BoqUtils.BOQ_STATUS_REPEAT_CODE);
            boq.setReason(BoqUtils.BOQ_STATUS_REPEAT_CODE_TEXT);
        } else {
            boq.setStatus(BoqUtils.BOQ_STATUS_NORMAL);
            boq.setReason("");
        }
        // 检查清单数据是否正确
        if (!BoqUtils.validateValue(boq.getUnit(), boq.getAmount(), boq.getPrice(), boq.getTotal())) {
            boq.setStatus(BoqUtils.BOQ_STATUS_INCOMPLETE);
            boq.setReason(BoqUtils.BOQ_STATUS_INCOMPLETE_TEXT);
        }
//        proBoqArrangeMapper.updateProBoqArrange(parentBoq);
        proBoqArrangeMapper.updateProBoqArrange(boq);
    }

    /**
     * 自动补全全部清单
     *
     * @param userName 登录用户
     * @return 结果
     */
    @Override
    public void autoComplementAll(String userName) {
        // 查询该用户下的所有清单
        ProBoqArrange search = new ProBoqArrange();
        search.setCreateBy(userName);
        List<ProBoqArrange> dataList = proBoqArrangeMapper.selectProBoqArrangeList(search);

        List<ProBoqArrange> updateList = new ArrayList<>();
        if (StringUtils.isNull(dataList) || dataList.size() == 0) {
            throw new ServiceException("未导入清单，不能进行自动补全");
        }
        Map<String, ProBoqArrange> dataMap = new HashMap<>(dataList.size());

        for (ProBoqArrange proBoqArrange : dataList) {
            dataMap.put(proBoqArrange.getBoqCode(), proBoqArrange);
        }
        for (int i = 0; i < dataList.size(); i++) {
            ProBoqArrange arrange = dataList.get(i);
            // 处理缺省清单
            if (arrange.getStatus() == BoqUtils.BOQ_STATUS_DEFECT) {
                String boqCode = arrange.getBoqCode();
                System.out.println("第" + arrange.getOrderNum() + "行，[" + boqCode + "]清单编号缺失。");
                String[] boqArray = boqCode.split("-");
                if (boqArray.length > 0) {
                    // 寻找向上临近不是叶子节点的清单
                    if (updateList.size() > 0) {
                        ProBoqArrange parent = new ProBoqArrange();
                        boolean flag = false;
                        for (int j = updateList.size() - 1; j > 0; j--) {
                            parent = updateList.get(j);
                            if (Constants.NO.equals(parent.getLeafNode())) {
                                flag = true;
                                System.out.println("找到父项：父项在第" + parent.getOrderNum() + "行，父项编号为：" + parent.getBoqCode());
                                break;
                            }
                        }
                        if (flag) {
                            // 找到父项清单，设置补全清单，如果补全清单的前缀，包含父项清单的后缀，则进行截取操作
                            String newBoqCode = "";
                            String parentCode = parent.getBoqCode();
                            if (parentCode.contains(Constants.BOQ_SEPARATOR)) {
                                String parentCodeSuffix = parentCode.substring(parentCode.lastIndexOf(Constants.BOQ_SEPARATOR));
                                if (boqCode.startsWith(parentCodeSuffix)) {
                                    newBoqCode = parentCode + boqCode.substring(parentCodeSuffix.length());
                                } else {
                                    newBoqCode = parentCode + boqCode;
                                }
                            } else {
                                newBoqCode = parentCode + boqCode;
                            }
                            arrange.setBoqCode(newBoqCode);
                            arrange.setParentCode(parent.getBoqCode());
                            arrange.setAncestors(parent.getAncestors() + "," + newBoqCode);
                            if (StringUtils.isNotEmpty(arrange.getUnit())) {
                                arrange.setLeafNode(Constants.YES);
                            } else {
                                arrange.setLeafNode(Constants.NO);
                            }
                            arrange.setLevel(parent.getLevel() + 1);
                            arrange.setAutoCompletion(Constants.YES);
                            arrange.setCompletionCode(parent.getBoqCode());
                            ProBoqArrange result = dataMap.get(newBoqCode);
                            if (StringUtils.isNotNull(result)) {
                                arrange.setStatus(BoqUtils.BOQ_STATUS_REPEAT_CODE);
                                arrange.setReason(BoqUtils.BOQ_STATUS_REPEAT_CODE_TEXT);
                            } else {
                                // 检查清单数据是否正确
                                if (!BoqUtils.validateValue(arrange.getUnit(), arrange.getAmount(), arrange.getPrice(), arrange.getTotal())) {
                                    arrange.setStatus(BoqUtils.BOQ_STATUS_INCOMPLETE);
                                    arrange.setReason(BoqUtils.BOQ_STATUS_INCOMPLETE_TEXT);
                                } else {
                                    arrange.setStatus(BoqUtils.BOQ_STATUS_NORMAL);
                                    arrange.setReason("");
                                }
                            }
                        }
                    }
                }
            }
            updateList.add(arrange);
        }
        proBoqArrangeMapper.updateBatch(updateList);
    }

    /**
     * 查询错误数据数量
     *
     * @param userName 登录用户
     * @return 错误数
     */
    @Override
    public int countErrorData(String userName) {
        return proBoqArrangeMapper.countErrorData(userName);
    }

}
